import axios from 'axios';
import EventEmitter from 'events';
import { gatewayEndpoint } from './util';
import {configurationService} from "./configService";


axios.defaults.headers.post['Content-Type'] = 'application/json';

export function getEnv(name) {
  return process.env[name];
}

export type JobId = string;

export interface SimulationContext {
  userId: string;
  appId: string;
  nodeId: string;
  notificationCallback: string;
}

export enum ParameterType {
  NUMBER = 'number',
  STRING = 'string',
  ARRAY = 'array',
  FILE = 'file'
}

export interface SimulationModel {
  type: string,
  file: string,
  entry?: string,
  name?: string
}

export interface SimulationParameter {
  name: string,
  value: any,
  unit?: string,
  type?: ParameterType,
  mdoLabel?: string,
  [prop: string]: any
}

export interface SimulationResult {
  ossPath: string,
  specifiedLocalPath?: string,
  uploadRawSimResult: boolean,
  specifiedOutputParams?: SimulationOutputParam[]
}

export interface SimulationOutputParam {
  name: string,
  unit?: string,
  mdoLabel?: string,
  [prop: string]: any
}

export interface SimulationSpec {
  driverVersion?: '1',
  runMode: 'native' | 'hpcc',
  model: SimulationModel,
  result?: SimulationResult,
  parameters?: SimulationParameter[],
  config?: {
    timeout?: number,
    [prop: string]: any
  }
  openGui: boolean,

  extendedProperty?: {
    [prop: string]: any;
  }
}

export interface SimulationJobDefinition {
  businessId?: string,
  desc?: string,
  product: string,
  spec: SimulationSpec
}

interface CreateSimulationJobRequest {
  context: SimulationContext;
  simServerIdentity: string;
  definition: SimulationJobDefinition;
}

export interface SimulationResultRequest {
  jobId: JobId;
  success: boolean;
  result: any;
  message: string;
  businessId: string;
  parameters?: any;
  info?: any;
}

export interface SimulationConfigTask {
  desc: string;
}

export interface ParamFile {
  name?: string;
  ossPath?: string;
}

export interface SimulationConfig extends EventEmitter {
  runMode?: 'native' | 'hpcc';
  model?: SimulationModel; // 模型
  inputSetup?: { // 输入参数设置
    type: string, // 手动编辑  批量编辑
    inputFile?: ParamFile // 输入文件信息
  };
  input?: SimulationParameter[]; // 输入参数
  outputSetup?: { // 输出参数设置
    type: string[], // 结果文件  指定参数
    outputFile: ParamFile // 输出文件信息
  };
  output?: SimulationOutputParam[]; // 输出参数
  result?: {
    nativePath?: string
  }; // 仿真结果设置
  task?: SimulationConfigTask; // 仿真任务
  simServerIdentity?: string[]; // 仿真服务器
  config?: {
    timeout?: number, // 超时时间
    [prop: string]: any
  };
  // 环境变量
  environment: {
    name: string,
    value: string
  }[];
  // 是否打开仿真软件GUI
  openGui: boolean;
  // 每个仿真软件独有的属性
  extra?: {
    [prop: string]: any;
  };
  // 从对象存储选择的模型文件地址
  modelOssPath?: string;
  // 并轨求解器
  solvers?: string[];
  // 并轨任务仿真服务器
  simServerIdentities?: {
    [prop: string]: string[];
  },
  // 并轨求解，外部businessId
  businessId?: string;
}


// in1 可以传入完整的仿真定义，可以对所有配置进行设置
export interface SimulationRequestIn1 {
  businessId?: string;
  desc?: string;
  model?: {
    file?: string,
    entry?: string,
    type?: string
  };
  outputParams?: SimulationOutputParam[],
  parametersFile?: string,
  openGui?: boolean,
  parameters?: SimulationParameter[],
  config?: {
    timeout?: number,
    [prop: string]: any
  },
  extra?: {
    [prop: string]: any;
  }
}

// in2 只能对 输入参数、仿真描述以及businessId进行设置(兼容design_id)
export interface SimulationRequestIn2 {
  businessId?: string,
  design_id?: string,
  desc?: string
  [prop: string]: any
}

export interface SimulationJobResult {
  simulationResultZip: string,
  specifiedParameters: {
    type: 'string' | 'file' | 'number' | 'array',
    name: string,
    value: any,
    [prop: string]: any
  }[]
}

export const SimJobStatus = {
  'created': 'created',
  'agentAssigned': 'agentAssigned',
  'agentDispatched': 'agentDispatched',
  'running': 'running',
  'succeed': 'succeed',
  'failed': 'failed'
};

export const SimJobStatusName = {
  'created': '排队中',
  'agentAssigned': '排队中',
  'agentDispatched': '排队中',
  'running': '正在运行',
  'succeed': '运行成功',
  'failed': '运行失败'
};

export interface Simulator extends EventEmitter {
  run(simulation: SimulationJobDefinition, simServerIdentity?: string): Promise<JobId>;
}

export class CommonSimulator extends EventEmitter implements Simulator {
  context: SimulationContext;

  constructor() {
    super();
    this.init();
  }

  init() {

    const userId = configurationService.config.envConfig.userId;//getEnv('SP_USER_ID');
    const appId = configurationService.config.envConfig.appId;//getEnv('SP_APP_ID');
    const nodeId = configurationService.config.envConfig.nodeId;//getEnv('SP_NODE_ID');

    this.context = {
      userId,
      appId,
      nodeId,
      "notificationCallback": "",
    };
  }

  async run(simulation: SimulationJobDefinition, simServerIdentity: string = ''): Promise<JobId> {
    this.context.nodeId = simulation.product;
    const request: CreateSimulationJobRequest = {
      context: this.context,
      simServerIdentity,
      definition: simulation
    };

    const createJobApi = `${gatewayEndpoint}/api/jobs`;
    const createResult = await axios.post(createJobApi, request);
    const { success, jobId, message } = createResult.data;
    if (success) {
      return jobId;
    }
    throw new Error(`create simulation job failed ${message}`);
  }
}

